{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "unsplash-image-search.ipynb",
      "provenance": [],
      "collapsed_sections": [
        "Ons94QRxCQR2",
        "lJVrkmy6DVj2",
        "ujCKerTnFBk4"
      ]
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "97qkK30wAzXb"
      },
      "source": [
        "# Unsplash Image Search\n",
        "\n",
        "Using this notebook you can search for images from the [Unsplash Dataset](https://unsplash.com/data) using natural language queries. The search is powered by OpenAI's [CLIP](https://github.com/openai/CLIP) neural network.\n",
        "\n",
        "This notebook uses the precomputed feature vectors for almost 2 million images from the full version of the [Unsplash Dataset](https://unsplash.com/data). If you want to compute the features yourself, see [here](https://github.com/haltakov/natural-language-image-search#on-your-machine).\n",
        "\n",
        "This project was created by [Vladimir Haltakov](https://twitter.com/haltakov) and the full code is open-sourced on [GitHub](https://github.com/haltakov/natural-language-image-search)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ons94QRxCQR2"
      },
      "source": [
        "## Setup Environment\n",
        "\n",
        "In this section we will setup the environment."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DYdIafWsOOUV"
      },
      "source": [
        "First we need to install CLIP and then upgrade the version of torch to 1.7.1 with CUDA support (by default CLIP installs torch 1.7.1 without CUDA). Google Colab currently has torch 1.7.0 which doesn't work well with CLIP."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "djgE7IjbV3sv"
      },
      "source": [
        "!pip install git+https://github.com/openai/CLIP.git\n",
        "!pip install torch==1.7.1+cu101 torchvision==0.8.2+cu101 -f https://download.pytorch.org/whl/torch_stable.html"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B7_Sk-T7DBEm"
      },
      "source": [
        "We can now load the pretrained public CLIP model."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_6FzbzS6W1R5"
      },
      "source": [
        "import clip\n",
        "import torch\n",
        "\n",
        "# Load the open CLIP model\n",
        "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
        "model, preprocess = clip.load(\"ViT-B/32\", device=device)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lJVrkmy6DVj2"
      },
      "source": [
        "## Download the Precomputed Data\n",
        "\n",
        "In this section the precomputed feature vectors for all photos are downloaded."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "18alAEjEOdSC"
      },
      "source": [
        "In order to compare the photos from the Unsplash dataset to a text query, we need to compute the feature vector of each photo using CLIP. This is a time consuming task, so you can use the feature vectors that I precomputed and uploaded to Google Drive (with the permission from Unsplash). If you want to compute the features yourself, see [here](https://github.com/haltakov/natural-language-image-search#on-your-machine).\n",
        "\n",
        "We need to download two files:\n",
        "* `photo_ids.csv` - a list of the photo IDs for all images in the dataset. The photo ID can be used to get the actual photo from Unsplash.\n",
        "* `features.npy` - a matrix containing the precomputed 512 element feature vector for each photo in the dataset.\n",
        "\n",
        "The files are available on [Google Drive](https://drive.google.com/drive/folders/1WQmedVCDIQKA2R33dkS1f980YsJXRZ-q?usp=sharing)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BAb15OJQZRkt"
      },
      "source": [
        "from pathlib import Path\n",
        "\n",
        "# Create a folder for the precomputed features\n",
        "!mkdir unsplash-dataset\n",
        "\n",
        "# Download the photo IDs and the feature vectors\n",
        "!gdown --id 1FdmDEzBQCf3OxqY9SbU-jLfH_yZ6UPSj -O unsplash-dataset/photo_ids.csv\n",
        "!gdown --id 1L7ulhn4VeN-2aOM-fYmljza_TQok-j9F -O unsplash-dataset/features.npy\n",
        "\n",
        "# Download from alternative source, if the download doesn't work for some reason (for example download quota limit exceeded)\n",
        "if not Path('unsplash-dataset/photo_ids.csv').exists():\n",
        "  !wget https://transfer.army/api/download/TuWWFTe2spg/EDm6KBjc -O unsplash-dataset/photo_ids.csv\n",
        "\n",
        "if not Path('unsplash-dataset/features.npy').exists():\n",
        "  !wget https://transfer.army/api/download/LGXAaiNnMLA/AamL9PpU -O unsplash-dataset/features.npy\n",
        "  "
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TVjuUh6oEtPt"
      },
      "source": [
        "After the files are downloaded we need to load them using `pandas` and `numpy`."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GQHcmMo1Ztjz",
        "outputId": "87cc44a3-668b-48a3-81f0-954c0c2a759f",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "import pandas as pd\n",
        "import numpy as np\n",
        "\n",
        "# Load the photo IDs\n",
        "photo_ids = pd.read_csv(\"unsplash-dataset/photo_ids.csv\")\n",
        "photo_ids = list(photo_ids['photo_id'])\n",
        "\n",
        "# Load the features vectors\n",
        "photo_features = np.load(\"unsplash-dataset/features.npy\")\n",
        "\n",
        "# Convert features to Tensors: Float32 on CPU and Float16 on GPU\n",
        "if device == \"cpu\":\n",
        "  photo_features = torch.from_numpy(photo_features).float().to(device)\n",
        "else:\n",
        "  photo_features = torch.from_numpy(photo_features).to(device)\n",
        "\n",
        "# Print some statistics\n",
        "print(f\"Photos loaded: {len(photo_ids)}\")"
      ],
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Photos loaded: 1981161\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ujCKerTnFBk4"
      },
      "source": [
        "## Define Functions\n",
        "\n",
        "Some important functions for processing the data are defined here.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pYVNtF-JFtfj"
      },
      "source": [
        "The `encode_search_query` function takes a text description and encodes it into a feature vector using the CLIP model."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "d0hmOh3qbcxK"
      },
      "source": [
        "def encode_search_query(search_query):\n",
        "  with torch.no_grad():\n",
        "    # Encode and normalize the search query using CLIP\n",
        "    text_encoded = model.encode_text(clip.tokenize(search_query).to(device))\n",
        "    text_encoded /= text_encoded.norm(dim=-1, keepdim=True)\n",
        "\n",
        "  # Retrieve the feature vector\n",
        "  return text_encoded"
      ],
      "execution_count": 5,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Vh1yyJtEGCAX"
      },
      "source": [
        "The `find_best_matches` function compares the text feature vector to the feature vectors of all images and finds the best matches. The function returns the IDs of the best matching photos."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "3TcmI5KIbe5F"
      },
      "source": [
        "def find_best_matches(text_features, photo_features, photo_ids, results_count=3):\n",
        "  # Compute the similarity between the search query and each photo using the Cosine similarity\n",
        "  similarities = (photo_features @ text_features.T).squeeze(1)\n",
        "\n",
        "  # Sort the photos by their similarity score\n",
        "  best_photo_idx = (-similarities).argsort()\n",
        "\n",
        "  # Return the photo IDs of the best matches\n",
        "  return [photo_ids[i] for i in best_photo_idx[:results_count]]"
      ],
      "execution_count": 6,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gEmt0F4iHbL0"
      },
      "source": [
        "The `display_photo` function displays a photo from Unsplash given its ID. \n",
        "\n",
        "This function needs to call the Unsplash API to get the URL of the photo and some metadata about the photographer. Since I'm [not allowed](https://help.unsplash.com/en/articles/2511245-unsplash-api-guidelines) to share my Unsplash API access key publicly, I created a small proxy that queries the Unsplash API and returns the data (see the code [here](https://github.com/haltakov/natural-language-image-search/tree/main/unsplash-proxy)). In this way you can play around without creating a developer account at Unsplash, while keeping my key private. I hope I don't hit the API rate limit.\n",
        "\n",
        "If you already have an Unsplash developer account, you can uncomment the relevant code and plugin your own access key."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "RC4HD8cBYOon"
      },
      "source": [
        "from IPython.display import Image\n",
        "from IPython.core.display import HTML\n",
        "from urllib.request import urlopen\n",
        "import json\n",
        "\n",
        "def display_photo(photo_id):\n",
        "  # Proxy for the Unsplash API so that I don't expose my access key\n",
        "  unsplash_api_url = f\"https://haltakov.net/unsplash-proxy/{photo_id}\"\n",
        "  \n",
        "  # Alternatively, you can use your own Unsplash developer account with this code\n",
        "  # unsplash_api_url = f\"https://api.unsplash.com/photos/{photo_id}?client_id=YOUR_UNSPLASH_ACCESS_KEY\"\n",
        "  \n",
        "  # Fetch the photo metadata from the Unsplash API\n",
        "  photo_data = json.loads(urlopen(unsplash_api_url).read().decode(\"utf-8\"))\n",
        "\n",
        "  # Get the URL of the photo resized to have a width of 480px\n",
        "  photo_image_url = photo_data[\"urls\"][\"raw\"] + \"&w=320\"\n",
        "\n",
        "  # Display the photo\n",
        "  display(Image(url=photo_image_url))\n",
        "\n",
        "  # Display the attribution text\n",
        "  display(HTML(f'Photo by <a target=\"_blank\" href=\"https://unsplash.com/@{photo_data[\"user\"][\"username\"]}?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">{photo_data[\"user\"][\"name\"]}</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>'))\n",
        "  print()"
      ],
      "execution_count": 7,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_3ojinZ0JYBC"
      },
      "source": [
        "Putting it all together in one function."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "LvUcljF5JcRn"
      },
      "source": [
        "def search_unslash(search_query, photo_features, photo_ids, results_count=3):\n",
        "  # Encode the search query\n",
        "  text_features = encode_search_query(search_query)\n",
        "\n",
        "  # Find the best matches\n",
        "  best_photo_ids = find_best_matches(text_features, photo_features, photo_ids, results_count)\n",
        "\n",
        "  # Display the best photos\n",
        "  for photo_id in best_photo_ids:\n",
        "    display_photo(photo_id)\n"
      ],
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xbym_cYJJH6v"
      },
      "source": [
        "## Search Unsplash\n",
        "\n",
        "Now we are ready to search the dataset using natural language. Check out the examples below and feel free to try out your own queries.\n",
        "\n",
        "> ⚠️ WARNING ⚠️ \n",
        "> Since many people are currently using the notebook, it seems that the Unsplash API limit is hit from time to time (even with caching in the proxy). I applied for production status which will solve the problem. In the meantime, you can just try when a new hour starts. Alternatively, you can use your own Unsplash API key."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-RmOFAq5NtlI"
      },
      "source": [
        "### \"Two dogs playing in the snow\""
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "CF7HuxAlFNXT",
        "outputId": "a084af95-42ca-403c-e728-0e30adfc9754",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 776
        }
      },
      "source": [
        "search_query = \"Two dogs playing in the snow\"\n",
        "\n",
        "search_unslash(search_query, photo_features, photo_ids, 3)"
      ],
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1583000058351-c6938bc10e22?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@richardworks?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Richard Burlton</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1541876176131-3f5e84a7331a?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@karlkiwi90?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Karl Anderson</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1491152237644-52bce1b55d40?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@samaritan_?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Xuecheng Chen</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PtaYocbjN0VQ"
      },
      "source": [
        "### \"The word love written on the wall\""
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "OswqrzaeMy1J",
        "outputId": "aa541ae5-cec6-4b82-d484-1ba82e030843",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 743
        }
      },
      "source": [
        "search_query = \"The word love written on the wall\"\n",
        "\n",
        "search_unslash(search_query, photo_features, photo_ids, 3)"
      ],
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1528037867495-ba242dd56ba5?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@damiangenton96?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Genton Damian</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1584285141681-76a0d45c044f?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@arozwadowska?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Anna Rozwadowska</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1589826000382-42984f7f523d?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@judebeck?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Jude Beck</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sUdySrczN4ZX"
      },
      "source": [
        "### \"The feeling when your program finally works\""
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "SRyCZMHQMzOP",
        "outputId": "72bdfad7-eca5-472a-c10c-90f232da54b9",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 839
        }
      },
      "source": [
        "search_query = \"The feeling when your program finally works\"\n",
        "\n",
        "search_unslash(search_query, photo_features, photo_ids, 3)"
      ],
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1533227268428-f9ed0900fb3b?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@brucemars?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">bruce mars</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1580810012067-bf854f9cbe93?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@lgnwvr?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">LOGAN WEAVER</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1509562967675-f7caeb234d48?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@vskvsk1?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Vasyl Skunziak</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aR4aDfQYN8J1"
      },
      "source": [
        "### \"The Syndey Opera House and the Harbour Bridge at night\""
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "wWkWfHhnMzZe",
        "outputId": "eabb87e8-6b6a-428d-cacd-e12c87d372a2",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 720
        }
      },
      "source": [
        "search_query = \"The Syndey Opera House and the Harbour Bridge at night\"\n",
        "\n",
        "search_unslash(search_query, photo_features, photo_ids, 3)"
      ],
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1524389054500-26845af32b1e?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@dilson?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Dalal Nizam</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1524387971136-0329ee358d44?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@dilson?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Dalal Nizam</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "<img src=\"https://images.unsplash.com/photo-1553899017-4ff76981a06e?ixid=MXwxOTkwNTV8MHwxfGFsbHx8fHx8fHx8&ixlib=rb-1.2.1&w=320\"/>"
            ],
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "Photo by <a target=\"_blank\" href=\"https://unsplash.com/@annatre?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Anna Tremewan</a> on <a target=\"_blank\" href=\"https://unsplash.com/?utm_source=NaturalLanguageImageSearch&utm_medium=referral\">Unsplash</a>"
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "\n"
          ],
          "name": "stdout"
        }
      ]
    }
  ]
}